﻿using HamcoWcs.Entitys.BaseConfigs;
using HamcoWcs.Entitys.BcrReadInfos;
using HamcoWcs.Entitys.DeviceErrors;
using HamcoWcs.Entitys.Logs;
using HamcoWcs.Entitys.Logss;
using HamcoWcs.Entitys.PalletInfos;
using HamcoWcs.Models.BaseConfigs;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.DeviceMsgs;
using HamcoWcs.Models.Devices;
using HamcoWcs.Models.Exceptions;
using HamcoWcs.Models.Monitors;
using HamcoWcs.Models.TibcoMessage;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace HamcoWcs.Workers
{
    public partial class PconWorker
    {

        /// <summary>处理接受信息</summary>
        private void DealRecv(PconPlc pconPlc)
        {
            // 接收输送机
            DealPconData(pconPlc);
            // 接受光栅数据
            DealRasterData(pconPlc);
            // 前端数据更新
            DealMonitor(pconPlc);
            // 处理全局配置（DB104）
            DealGlobalConfig(pconPlc);

            try
            {
                // 获取电箱数据
                DealCabinetPara(pconPlc);
            }
            catch (Exception ex)
            {

            }

            // 获取读码数据
            DealBcrData(pconPlc);
            // 设置超时搬送时间
            DealThresholdData(pconPlc);
            // 获取RGV定位信息
            DealRgvPosition(pconPlc);
            // 获取报警点位信息
            DealSecurityData(pconPlc);
            // 重置里程
            DealResetMileage(pconPlc);
            // 获取读码率
            GetBcrRate(pconPlc);
        }
        
        private void DealThresholdData(PconPlc pconPlc)
        {
            var thresholds = _monitorBaseService.GetMonitorData().ThresholdMonitors;
            var content = pconPlc.DbInfo.FirstOrDefault(x => x.DbNum == 104).Buffer;


            foreach (var threshold in thresholds)
            {
                threshold.Update(content);
                if (threshold.Cmd > 0)
                {
                    var a = pconPlc.Client.DBWrite(104, threshold.Offset, 2, BitConverter.GetBytes(threshold.Cmd).Reverse().ToArray());
                    if (a == 0)
                    {
                        threshold.Cmd = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 获取RGV定位信息
        /// </summary>
        /// <param name="pconPlc"></param>
        private void DealRgvPosition(PconPlc pconPlc)
        {
            foreach (var con in pconPlc.Pcons.Values)
            {
                if (GlobalValue.RgvPositionDic.ContainsKey(con.MachineName) && con.RgvPosition == 0)
                {
                    var t = GlobalValue.RgvPositionDic[con.MachineName];

                    var buffer = pconPlc.DbInfo.FirstOrDefault(x => x.DbNum == 103).Buffer;

                    var t1 = buffer.Skip(t).Skip(4).Reverse().ToArray();

                    UInt32 position = BitConverter.ToUInt32(t1);
                    if (position == 0)
                    {
                        // 防止一直读取
                        position++;
                    }
                    con.RgvPosition = position;
                }
            }
        }

        private void DealResetMileage(PconPlc pconPlc)
        {
            if (_asrs.MotorReset.Count <= 0) return;

            for (int i = _asrs.MotorReset.Count - 1; i >= 0; i--)
            {
                var m = _asrs.MotorReset[i];
                var res = pconPlc.Client.DBWrite(103, m.GetStart(), 2, new byte[] { 0, 0 });

                if (res == 0)
                {
                    _asrs.MotorReset.Remove(m);
                }
            }
        }

        private void GetBcrRate(PconPlc plc)
        {
            if (ReadRateWorker.CVBcrReadFlag)
            {
                try
                {
                    var content = plc.DbInfo.First(x => x.DbNum == 103).Buffer;

                    foreach (var bcr in PconBcrRate.BcrRates)
                    {
                        bcr.Update(content);
                    }

                    var now = DateTime.Now;
                    var setTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
                    setTime = setTime.AddHours(-1);


                    var readRates = PconBcrRate.BcrRates.Select(x => new BcrReadInfo(x.Name, x.ReadCount, x.FaliureCount, setTime));

                    var flag = new byte[] { 0x01, 0x00 };
                    var res = plc.Client.DBWrite(103, 736, 2, flag);

                    lock (ReadRateWorker.Lock)
                    {
                        ReadRateWorker.ReadInfos.AddRange(readRates);
                    }
                }
                catch (Exception)
                {

                }

                ReadRateWorker.CVBcrReadFlag = false;
            }
        }
        private void DealCabinetPara(PconPlc pconPlc)
        {
            var cabinetParas = _monitorBaseService.GetMonitorData().CabinetParas;
            var content = pconPlc.DbInfo.First(x => x.DbNum == 103).Buffer;

            foreach (var cabinetPara in cabinetParas)
            {
                cabinetPara.Update(content);
            }
        }

        private void DealBcrData(PconPlc pconPlc)
        {
            var bcrMonitors = _monitorBaseService.GetMonitorData().BCRMonitors;
            var content = pconPlc.DbInfo.First(x => x.DbNum == 104).Buffer;

            foreach (var bcrMonitor in bcrMonitors)
            {
                bcrMonitor.Update(content);

                if (bcrMonitor.Cmd != 0)
                {
                    var recv = new byte[1];
                    var a = pconPlc.Client.DBRead(104, bcrMonitor.Offset, 1, recv);

                    var setFlag = 0;
                    if (bcrMonitor.Cmd == 2)
                    {
                        setFlag = 1;
                    }

                    if (a == 0)
                    {
                        var send = recv.First().SetBit(bcrMonitor.Position, setFlag);
                        pconPlc.Client.DBWrite(104, bcrMonitor.Offset, 1, new byte[] { send });
                        bcrMonitor.Cmd = 0;
                    }
                }
            }
        }

        private void DealSecurityData(PconPlc pconPlc)
        {
            var monitorData = _monitorBaseService.GetMonitorData();

            var errorBits = monitorData.ErrorBits;
            var db3 = pconPlc.DbInfo.FirstOrDefault(x => x.DbNum == 103);

            if (db3 == null) return;

            var errors = _wcsDbContext.DeviceErrorQueues.ToList();

            foreach (var b in errorBits)
            {
                b.GetTargetBit(db3.Buffer);

                if (b.CurrentValue != b.OldValue && b.CurrentValue >= 0)
                {
                    if (b.CurrentValue == 0)
                    {
                        var d = _wcsDbContext.DeviceErrorQueues.FirstOrDefault(x => x.MachineName == b.DeviceName);

                        if (d != null)
                        {
                            d.LastUpdateTime = DateTime.Now;
                            var duration = d.LastUpdateTime - d.CreatedTime;

                            if (duration.TotalSeconds <= 5) continue;

                            var l = new DeviceErrorLog()
                            {
                                SetTime = duration.GetDuration(),
                                CreatedTime = d.CreatedTime,
                                LastUpdateTime = d.LastUpdateTime,
                                DeviceName = d.MachineName,
                                ErrorCode = d.ErrorCode,
                                ErrorDetail = d.ErrorDetail,
                                PlcName = d.PlcName,
                            };
                            _wcsDbContext.DeviceErrorLogs.Add(l);
                            _wcsDbContext.DeviceErrorQueues.Remove(d);
                            _wcsDbContext.SaveChanges();
                            _mesCommunicateService.AlarmReportSet(d);
                        }
                        // 恢复
                    }

                    if (b.CurrentValue == 1)
                    {
                        // 设置
                        var err = _wcsDbContext.DeviceErrorQueues.AsNoTracking().FirstOrDefault(x => x.MachineName == b.DeviceName);

                        if (err == null)
                        {
                            var d = new DeviceErrorQueue()
                            {
                                CreatedTime = DateTime.Now,
                                LastUpdateTime = DateTime.Now,
                                ErrorCode = "1",
                                ErrorDetail = b.Name,
                                ErrorLevel = "1",
                                MachineName = b.DeviceName,
                                PortName = "",
                                PlcName = pconPlc.PlcName
                            };


                            _wcsDbContext.DeviceErrorQueues.Add(d);
                            _wcsDbContext.SaveChanges();
                            _mesCommunicateService.AlarmReportClear(d);
                        }
                    }
                }

            }
        }

        private void DealGlobalConfig(PconPlc plc)
        {
            var buffer = plc.DbInfo.FirstOrDefault(x => x.DbName == "other_send").Buffer;

            foreach (var cfg in GlobalValue.PconGlobalConfigs.Values)
            {
                var b = buffer.Skip(cfg.Offset).Take(cfg.Length).Reverse().ToArray();
                var value = BitConverter.ToUInt16(b);

                //if (cfg.Name == "CJSTW100STATE" || cfg.Name == "CJSTW200STATE")
                //{
                //    if (cfg.CurrentValue != value.ToString())
                //    {

                //        var machineName = cfg.Name == "CJSTW100STATE" ? "CJSTW100" : "CJSTW200";
                //        var f = value.ToString() == "0" ? "HIGH" : "LOW";

                //        _mesCommunicateService.MachineFrequencyRequest(machineName, f);
                //        _config.SetConfigMsg(cfg.Name, f);

                //        var de = new DeviceEvent()
                //        {
                //            MachineName = cfg.Name[..8],
                //            PortName = "",
                //            Description = f,
                //            SetTime = DateTime.Now,
                //        };
                //        _wcsDbContext.Set<DeviceEvent>().Add(de);
                //        _wcsDbContext.SaveChanges(); ;
                //    }
                //}
                cfg.CurrentValue = value.ToString();
            }

            var globalData = _monitorBaseService.GetMonitorData().GlobalConfig;

            foreach (var pi in globalData.GetType().GetProperties())
            {
                if (GlobalValue.PconGlobalConfigs.ContainsKey(pi.Name))
                {
                    pi.SetValue(globalData, GlobalValue.PconGlobalConfigs[pi.Name].CurrentValue);
                }
            }
        }

        /// <summary>处理输送机信息</summary>
        private void DealPconData(PconPlc pconPlc)
        {
            var dbInfo = pconPlc.DbInfo.FirstOrDefault(x => x.DbName == "recv")
                ?? throw new Exception("DealRasterData:未找到对应的DB数据");
            var recv = dbInfo.Buffer;

            // 38991   OFFSET 4032
            //var b = recv.Skip(4032).Take(4).Reverse().ToArray();
            //var a= BitConverter.ToInt32(b);
            foreach (var con in pconPlc.Pcons.Values)
            {
                if (con.PconName == 9999) continue;
                //根据偏移量找到输送机对应的数据，并进行更新
                var msg = recv.Skip(con.RecvStartPoint).Take(GlobalValue.CV_RECV_MSG_SIZE).ToArray();
                var msgDto = new PconRecvMsg(msg);

                // 根据状态变化给MES上报消息              
                _pconStateService.PconStateChangedReport(con, msgDto);
                con.Update(msgDto);

                if (con.Request == 0) continue;

                //如果Plc有消息request，进行消息处理
                _communicationLogs.Add(new CommunicationLog("WCS << PCON")
                {
                    TransactionId = $"{DateTime.Now:yyyyMMddHHmmssffffff}",
                    Receiver = "WCS",
                    Sender = con.DeviceName,
                    Content = msgDto.ToJson(),
                    MessageName = ((EnumPconRecvMsg)msgDto.Request).ToString(),
                    MessageStatus = "",
                    MessageType = "",
                    Return = "",
                    UnitId = msgDto.UnitId,
                    CreatedTime = DateTime.Now,
                });

                var parser = _pconMsgParseFactory.CreateParser(con);
                if (parser is null)
                {
                    _logger.AddSystemErrorLog($"PconWorker->DoWork->DealPconData:CreateParser has not found valid parser.");
                    continue;
                }

                try
                {
                    parser.Deal(con, pconPlc);
                    //处理完成清除request标记
                    pconPlc.ClearRequest(con, dbInfo);
                }
                catch (WarningException ex)
                {
                    Console.WriteLine(ex.Message);
                }
                catch (Exception ex)
                {

                }
            }
        }

        /// <summary>处理安全光栅信息</summary>
        private void DealRasterData(PconPlc pconPlc)
        {
            var dbInfo = pconPlc.DbInfo.FirstOrDefault(x => x.DbName == "other_recv")
                ?? throw new Exception("DealRasterData:未找到对应的DB数据");
            var recv = dbInfo.Buffer;

            foreach (var raster in pconPlc.Rasters)
            {
                raster.UpdateRecv(recv);
            }
        }

        /// <summary>处理安全光栅信息</summary>
        private void DealMonitor(PconPlc pconPlc)
        {
            var monitorData = _monitorBaseService.GetMonitorData();
            var condata = monitorData.MonitorConDatas;

            var pallets = _wcsDbContext.Set<PalletInfo>().AsNoTracking()
                .Where(x => !string.IsNullOrEmpty(x.PalletType))
                .ToDictionary(k => k.UnitId, v => v);

            foreach (var con in pconPlc.Pcons.Values)
            {
                // 获取栈板类型给前端显示
                if (con.IsGoods == 1 && !string.IsNullOrEmpty(con.UnitId))
                {
                    var a = pallets.TryGetValue(con.UnitId, out PalletInfo pallet);
                    if (a)
                    {
                        con.PalletType = pallet.PalletType;
                    }
                }

                var conmonitor = condata.FirstOrDefault(x => x.Name == $"{con.MachineName}-{con.PortName}");
                if (conmonitor == null)
                {
                    condata.Add(new MonitorConData(con));
                }
                else
                {
                    conmonitor.Update(con);
                }

                var ppkstatus = monitorData.PpkStatus;
                var db103 = pconPlc.DbInfo.FirstOrDefault(x => x.DbNum == 103);
                for (var i = 0; i < ppkstatus.Count; i++)
                {
                    var t = BitConverter.ToUInt16(db103.Buffer.Skip(716 + (2 * i)).Take(2).ToArray());
                    ppkstatus[i] = t;
                }
            }

            var monitorRasters = monitorData.Rasters;
            foreach (var raster in pconPlc.Rasters)
            {
                var uiraster = monitorRasters.FirstOrDefault(x => x.Name.Equals(raster.Name));
                if (uiraster == null)
                {
                    monitorRasters.Add(new UIRaster(raster));
                }
                else
                {
                    if (uiraster.BypassFlag != raster.BypassFlag)
                    {
                        var r = _wcsDbContext.Rasters.FirstOrDefault(x => x.Name == raster.Name);
                        if (r != null)
                        {
                            r.Remark = raster.BypassFlag ? $"{DateTime.Now:yyyy-MM-dd HH:mm:ss},设备端禁用" : "";
                            raster.Remark = r.Remark;
                        }
                    }
                    uiraster.Update(raster);
                }
            }

            _wcsDbContext.SaveChanges();
        }




        
    }
}
